package com.kl.model.base;

import com.kl.App;
import com.kl.TankGame;
import com.kl.constant.AttackModel;
import com.kl.constant.TankModel;
import com.kl.constant.Windows;
import com.kl.enums.Direct;
import com.kl.enums.State;
import com.kl.enums.TankType;
import com.kl.exceptions.DeathException;
import com.kl.model.pojo.EnemyTank;
import com.kl.model.pojo.HeroTank;
import com.kl.model.pojo.Shoot;
import com.kl.model.pojo.Tank;
import com.kl.utils.CollectionUtils;
import lombok.AllArgsConstructor;
import lombok.Data;

import java.awt.*;
import java.io.Closeable;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @author CC
 * time 2024-05-14
 * description
 *  坦克抽象基类
 */
@Data
@AllArgsConstructor
public abstract class AbstractTank implements Move,Attack {
    /**
     * 坦克类型
     */
    private TankType origin;
    /**
     * x轴坐标,代表中心位置
     */
    private int x;
    /**
     * y轴坐标,代表中心位置
     */
    private int y;
    /**
     * 坦克移动速度
     */
    private int speed;
    /**
     * 单位时间内坦克的攻击次数 (1s)
     */
    private int times;
    /**
     * 每次攻击后的间隔时间 , 单位 ms
     */
    private int interval;
    /**
     * 坦克移动方向
     */
    private Direct direct;
    /**
     * 坦克状态
     */
    private volatile State status;
    /**
     * 持有的武器
     */
    private volatile CopyOnWriteArrayList<AbstractAttack> attacks;

    public AbstractTank(){
        this(null,0,0,2, AttackModel.DEFAULT_TIMES,
                AttackModel.DEFAULT_INTERVAL, Direct.UP, State.ALIVE,new CopyOnWriteArrayList<>());
    }
    public boolean isTouch(){
        if (status== State.DEATH) {
            return false;
        }
        if (TankGame.isEnd()) {
            return false;
        }
        ArrayList<Tank> tanks = new ArrayList<>();
        tanks.addAll(CollectionUtils.orEmpty(TankGame.getPlayers(), HeroTank.class));
        tanks.addAll(CollectionUtils.orEmpty(TankGame.getEnemies(), EnemyTank.class));
        if (CollectionUtils.isEmpty(tanks)) {
            return false;
        }
        for (Tank tank : tanks) {
            if (!this.equals(tank)) {
                if (new Rectangle(tank.getX(),tank.getY(), TankModel.BODY_SIZE,TankModel.BODY_SIZE).intersects(
                        new Rectangle(getX(),getY(),TankModel.BODY_SIZE,TankModel.BODY_SIZE))) {
                    return true;
                }
            }
        }
        return false;
    }
    @Override
    public void move(int x, int y, int speed, Direct direct) {
        this.setDirect(direct);
        if(isTouch()){
            return;
        }
        //行走
        switch (direct){
            case UP:
                if(y- TankModel.PIPED_LENGTH -speed>0){
                    this.setY(y-speed);
                }
                break;
            case DOWN:
                if(y+TankModel.PIPED_LENGTH+speed< Windows.HEIGHT){
                    this.setY(y+speed);
                }
                break;
            case LEFT:
                if(x-TankModel.PIPED_LENGTH-speed>0){
                    this.setX(x-speed);
                }
                break;
            case RIGHT:
                if(x+TankModel.PIPED_LENGTH+speed<Windows.WIDTH){
                    this.setX(x+speed);
                }
                break;
        }
    }


    @Override
    public boolean attack(int x, int y, Direct direct, Object object,TankType origin) {
        if (attacks==null) {
            throw new DeathException();
        }
        if(attacks.stream().filter(i->i.getState().equals(State.ALIVE)).count()>=AttackModel.DEFAULT_CAPACITY){
            return false;
        }
        //新增子弹库存
        for (int i = 0; i < times; i++) {
            Shoot bean = ShootFactory.getObject(x, y, direct,origin);
            attacks.add(bean);
            CompletableFuture.runAsync(bean, App.getPOOL());
        }
        try {
            int interval1 = getInterval();
            if (interval1==0) {
                return false;
            }
            Thread.sleep(interval1);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return false;
    }

}
